#ifndef GNLDATAMODEL_H
#define GNLDATAMODEL_H

#include "gnlVector3.h"
#include "gnlTexture.h"
#include <string>
#include <vector>


using namespace std;
/*
class gnlUV{
public:
	float uv[2];
};
*/
/*
class gnlDataArray{

public:
	
	
};
*/

class gnlUVCoords{
public:
	float u;
	float v;

	gnlUVCoords():u(0), v(0){}
	gnlUVCoords(float _u, float _v):u(_u), v(_v){}
	void set (float _u, float _v){u = _u; v = _v;}
};
/*
class gnlDataTexture{

public:

	string	name;
	double transparencyFactor;

	string fileName;
	int oglId; // Internal Id in OpenGL


	gnlTexture(string name, string fileName, double transparencyFactor = 0){
		this->transparencyFactor = transparencyFactor;
		this->name = name;
		this->fileName = fileName;
	}

	void setTransparencyFactor(float transparencyFactor){this->transparencyFactor = transparencyFactor;}

};
*/

class gnlMaterial{

private:
	void setReflectance(float *reflectance, float r, float g, float b, float a){	
		reflectance[0] = r;
		reflectance[1] = g;
		reflectance[2] = b;
		reflectance[3] = a;
	}
public:
	string name; // nome do material
	//int id; //Not utilized, the systems work with indices id 

	//All materials have your material colors 
	float ambientReflectance[3];
	float diffuseReflectance[3];
	float emissiveReflectance[3];
	float specularReflectance[3];
	float shininess;
	float transparencyFactor;

	//Supported texture layers
	//diffuseTexture is vector to support compose textures(sub mat create multiple materials with 1 diffuseTexture)
	vector<gnlTexture*> diffuseTexture; //Diffuse texture support multitexture
	gnlTexture *bumpTexture; // Utilized for bump(normalmap etc)

	gnlMaterial(){ transparencyFactor = 1;}
	bool haveDiffuseTexture(){return (diffuseTexture.size()>= 1); }

	void setAmbientReflectance(float r, float g, float b, float a){
		setReflectance(ambientReflectance, r, g, b, a);
	}

	void setDiffuseReflectance(float r, float g, float b, float a){
		setReflectance(diffuseReflectance, r, g, b, a);
	}

	void setSpecularReflectance(float r, float g, float b, float a){
		setReflectance(specularReflectance, r, g, b, a);
	}

	void setEmissiveReflectance(float r, float g, float b, float a){
		setReflectance(emissiveReflectance, r, g, b, a);
	}

	void setShininess(float shininess){
		this->shininess = shininess;
	}

	float* getAmbientReflectance(){
		return ambientReflectance;
	}
	
	float* getDiffuseReflectance(){
		return diffuseReflectance;
	}

	float* getSpecularReflectance(){
		return specularReflectance;
	}

	float* getEmissiveReflectance(){
		return emissiveReflectance;
	}

	float* getShininess(){
		return &shininess;
	}
	

	//gnlMaterial(const int materialId, string textureName){
	//id = materialId;
	//this->textureName = textureName;
	//}


};

class gnlTriangle{
public:
	
	int vertexIndex[3];	//Index of vertices 
	gnlUVCoords uvCoord[3]; //UV coordinates 
	gnlVector3 normal[3]; //Normal vector for each triangle vertex
	gnlVector3 binormal[3];
	gnlVector3 tangent[3];
	int materialIndex;	//Material utilized in triangle

	gnlTriangle(){
		binormal[0].set(0,0,0);
		binormal[1].set(0,0,0);
		binormal[2].set(0,0,0);

		tangent[0].set(0,0,0);
		tangent[1].set(0,0,0);
		tangent[2].set(0,0,0);

		normal[0].set(0,0,0);
		normal[1].set(0,0,0);
		normal[2].set(0,0,0);
	}
};


class gnlMesh{
public:
	string name; //node//mesh name(One node in FBX is an instance of gnlMesh)
	
	gnlTriangle *pTriangle;
	int numberOfTriangles;

	gnlVector3 *pVertex;
	int numberOfVertices;

	
	//Tangent space bases
	/*ADICIONAR NULL NESTES VETORES NO CONSTRUTOR
	gnlVector3 *pTangent;
	gnlVector3 *pBitangent;
	*/

	gnlMesh():numberOfTriangles(0), numberOfVertices(0),
			 			  pTriangle(NULL), pVertex(NULL){ }

	gnlMesh(string _name):numberOfTriangles(0), numberOfVertices(0),
			  pTriangle(NULL), pVertex(NULL), 
			  name(_name) { }


	inline const gnlVector3& getVertex(int triangleIndex, int vertexIndex){
		return pVertex[ pTriangle[triangleIndex].vertexIndex[vertexIndex] ];//Not verify index out of bound to increase performance
	}

	inline const gnlVector3& getNormal(int triangleIndex, int vertexIndex){
		return pTriangle[triangleIndex].normal[vertexIndex];
	}

	inline const gnlUVCoords& getUVCoord(int triangleIndex, int vertexIndex){
		return pTriangle[triangleIndex].uvCoord[vertexIndex];
	}

	inline int getMaterial(int triangleIndex){
		return pTriangle[triangleIndex].materialIndex;
	}

};


class gnlScene{
public:
	
	vector<gnlMaterial*> material; //All materials in scene
	int numberOfMaterials;

	vector<gnlMesh*> mesh; //A model have 1 or more mesh nodes

	int numberOfMeshes; 

	gnlScene():numberOfMaterials(0),numberOfMeshes(0){}
	void destroy(){
		
		for(unsigned int i = 0; i < material.size(); i++){
			delete material[i];
		}
		/*
		if(pMaterial){
			if(numberOfMaterials>1)
				delete []pMaterial;else
				delete pMaterial;
		}
		
		*/
		for(unsigned int i = 0; i < mesh.size(); i++){
			delete mesh[i];
		}
		/*
		if(pMesh){
			if(numberOfMeshs>1)
				delete []pMesh;else
				delete pMesh;
		}

		*/


	}
	

};
#endif